package memorylib

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/StackExchange/wmi"
	"github.com/urfave/cli/v2"
	"os"
)

var (
	BuildTime string
	Version   = "1.0.0"
)

func Do() {
	app := &cli.App{
		Name:    "memory",
		Version: fmt.Sprintf("%s build:%s", Version, BuildTime),
		UsageText: "eg: memory -a \n " +
			"-a 可选值 all返回所有内存信息 \n" +
			"\n",
		Description: "进行内存查询",
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:        "a",
				Value:       false,
				DefaultText: "false",
			},
		},
		Action: func(ctx *cli.Context) error {
			var (
				a          bool
				basememory []MemoryBaseInfo
				allmemory  []MemoryAllInfo
				err        error
				bs         []byte
			)
			a = ctx.Bool("a")
			if !a {
				basememory, err = GetBaseMemoryInfo()
				if err != nil {
					return cli.Exit(fmt.Sprintf("获取内存信息时发生错误:%s", err.Error()), 1)
				}
				bs, err = json.Marshal(basememory)
			} else {
				allmemory, err = GetAllMemoryInfo()
				if err != nil {
					return cli.Exit(fmt.Sprintf("获取内存信息时发生错误:%s", err.Error()), 1)
				}
				bs, err = json.Marshal(allmemory)
			}
			w := bufio.NewWriter(os.Stdout)
			w.WriteString(string(bs) + "\n")
			w.Flush()
			return nil
		},
	}
	if err := app.Run(os.Args); err != nil {
		fmt.Printf("命令行调用错误：%s ，请查看帮助文档", err.Error())
	}
}

func GetBaseMemoryInfo() (data []MemoryBaseInfo, err error) {
	data = make([]MemoryBaseInfo, 0)
	err = wmi.Query("SELECT * FROM Win32_PhysicalMemory", &data)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func GetAllMemoryInfo() (data []MemoryAllInfo, err error) {
	data = make([]MemoryAllInfo, 0)
	err = wmi.Query("SELECT * FROM Win32_PhysicalMemory", &data)
	if err != nil {
		return nil, err
	}
	return data, nil
}

type MemoryBaseInfo struct {
	Capacity    uint64 // eg:8589934592 ，获取内存容量, / 1024*1024*1024 才能换算成GB
	Description string // eg:物理内存 ，物理内存还虚拟内存
	//ConfiguredClockSpeed uint32 //eg；2133 (0x855) ，配置时钟速度
	//ConfiguredVoltage    uint32 // eg：1200 (0x4B0) ，配置电压
	DataWidth    uint16 // eg：64，获取内存数据带宽
	Manufacturer string // eg：859B，生产商
	//MaxVoltage uint32 // eg：1200 ，最大电压
	//MinVoltage uint32 // eg：1200 ，最小电压
	Model        string // eg：null ，型号 // 不清楚是我电脑的问题还是其他什么原因
	PartNumber   string // eg：CT8G4DFS8266.M8FE   ，零件编号,由生产商定义
	SerialNumber string // eg：2271E66A，编号
	SKU          string // eg：null，SKU号 // 不清楚是我电脑的问题还是其他什么原因
	Speed        uint32 // eg：2667，速率 内存频率 单位MHz
	Tag          string // eg：Physical Memory 0，唯一标识符的物理存储器
}

// wmi 能获取到 的 全部 memory 信息
type MemoryAllInfo struct {
	Capacity uint64 // 获取内存容量（单位字节）
	Caption  string // 物理内存还虚拟内存
	//ConfiguredClockSpeed uint32 //配置时钟速度
	//ConfiguredVoltage    uint32 // 配置电压
	CreationClassName   string // 创建类名（就是更换这个类的名字）
	DataWidth           uint16 // 获取内存带宽
	Description         string // 描述更Caption一样
	DeviceLocator       string // 获取设备定位器
	FormFactor          uint16 // 构成因素
	HotSwappable        bool   // 是否支持热插拔
	InterleaveDataDepth uint16 // 数据交错深度
	InterleavePosition  uint32 // 交错的位置
	Manufacturer        string // 生产商
	//MaxVoltage uint32 // 最大电压
	MemoryType uint16 // 内存类型
	//MinVoltage uint32 // 最小电压
	Model                string // 型号
	Name                 string // 名字
	OtherIdentifyingInfo string // 其他识别信息
	PartNumber           string // 零件编号
	PositionInRow        uint32 // 行位置
	PoweredOn            bool   // 是否接通电源
	Removable            bool   // 是否可拆卸
	Replaceable          bool   // 是否可更换
	SerialNumber         string // 编号
	SKU                  string // SKU号
	SMBIOSMemoryType     uint32 // SMBIOS内存类型
	Speed                uint32 // 速率
	Status               string // 状态
	Tag                  string // 唯一标识符的物理存储器
	TotalWidth           uint16 // 总宽
	TypeDetail           uint16 // 类型详细信息
	Version              string // 版本信息
}
